﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Common.Algo
{
    class BoyerMooreSearch
    {
        public string searchword{get;private set;}
        /// <summary>
        /// 坏字符规则表
        /// </summary>
        Dictionary<char, List<int>> dictCharIndex = new Dictionary<char, List<int>>();
        /// <summary>
        /// 好后缀规则表
        /// </summary>
        Dictionary<string, string> dictPrefixIndex = new Dictionary<string, string>();

        public BoyerMooreSearch(string sword)
        {
            searchword = sword;
            if (string.IsNullOrEmpty(searchword))
            {
                throw new ArgumentNullException();
            }
            for (int i = 0; i < searchword.Length; i++)
            {
                char ch = searchword[i];
                if (dictCharIndex.ContainsKey(ch))
                {
                    dictCharIndex[ch].Add(i);
                }
                else
                {
                    dictCharIndex.Add(ch, new List<int>() { i });
                }
                string str = searchword.Substring(0, i + 1);
                dictPrefixIndex.Add(str, "");
            }
        }
        
        public int Serach(string content)
        {
            if(string.IsNullOrEmpty(content))
            {
                 throw new ArgumentNullException();
            }

            int offset = 0;
            string prefix = "";
            string goodsuffix = "" ;
            for (int i = 0; i < content.Length; i += offset)
            {
                if (i + searchword.Length > content.Length)
                {
                    break;
                }
                prefix = "";
                goodsuffix = "";
                int gsoffset = 0;
                bool finded = true;
                for (int j = searchword.Length - 1; j > -1; j--)
                {
                    char ch = searchword[j];
                    char srcch = content[i + j];
                    if (srcch == ch)
                    {
                        goodsuffix  = searchword.Substring(j, searchword.Length - j);
                        if (dictPrefixIndex.ContainsKey(goodsuffix))
                        {
                            prefix = goodsuffix;
                        }
                    }
                    else
                    {
                        finded = false;
                        //后移位数 = 坏字符的位置 - 搜索词中的上一次出现位置(上一次位置：如果有多个坏字符，指搜索词的最后坏字符的一个位置)
                        if (dictCharIndex.ContainsKey(srcch))
                        {
                            offset = j - dictCharIndex[srcch][dictCharIndex[srcch].Count-1];
                        }
                        else
                        {
                            offset = j + 1;
                        }
                        //当有好后缀时
                        if (goodsuffix != "")
                        {
                            //后移位数 = 好后缀的位置 - 搜索词中的上一次出现位置.如果不存在。则上一次位置为-1

                            //如果有后缀在前缀位置
                            if (prefix != "")
                            {
                                gsoffset = searchword.Length - prefix.Length;
                            }
                            else
                            {
                                gsoffset = searchword.Length;
                            }
                        }
                        //比较谁的位移大
                        if (gsoffset > offset)
                        {
                            offset = gsoffset;
                        }
                        break;
                    }
                }
                if (finded)
                {
                    return i;
                }

            }
            return -1;
        }
    }
}
